#include <iostream>
template <typename T>
struct is_pointer{
  enum{ value=false };
};
template <typename T>
struct is_pointer<T*>{
  enum{ value=true };
};
template <typename T>
void foo(T v){
  if(is_pointer<T>::value){
    std::cout<<"POINTER"<<std::endl;
  }else{
    std::cout<<"NOT POINTER"<<std::endl;
  }
}
int main(void){
  int n=7;
  
  foo(n);
  foo(&n);
  
  return 0;
}
enum 대신에 static constexpr나 using 등을 사용할 수 있다.
template <typename T>
struct is_pointer{
  static constexpr bool value=false;
};
template <typename T>
struct is_pointer<T*>{
  static constexpr bool value=true;
};
template <typename T>
struct is_pointer<T* const>{
  static constexpr bool value=true;
};
template <typename T>
struct is_pointer<T* volatile>{
  static constexpr bool value=true;
};
template <typename T>
struct is_pointer<T* const volatile>{
  static constexpr bool value=true;
};
배열의 경우
#include <iostream>
template <typename T>
struct is_array{
  static constexpr bool value=false;
};
template <typename T, size_t N>
struct is_array<T[N]>{
  static constexpr bool value=true;
};
template <typename T>
struct is_array<T[]>{
  static constexpr bool value=true;
};
template <typename T>
void foo(T& a){
  if(is_array<T>::value){
    std::cout<<"Array"<<std::endl;
  }else{
    std::cout<<"NOT ARRAY"<<std::endl;
  }
}
int main(void){
  int arr[5]={1, 2, 3, 4, 5};
  foo(arr);
}